package com.disk.aspect;


import com.disk.annotation.GlobalInterceptor;
import com.disk.annotation.VerifyParam;
import com.disk.entity.constants.Constants;
import com.disk.entity.dto.SessionWebUserDto;
import com.disk.entity.enums.ResponseCodeEnum;
import com.disk.exception.BusinessException;
import com.disk.utils.StringTools;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

@Aspect
@Component
public class GlobalOperationAspect {

    private static final Logger logger = LoggerFactory.getLogger(GlobalOperationAspect.class);

    @Pointcut("@annotation(com.disk.annotation.GlobalInterceptor)")
    private void requestInterceptor() {

    }


    @Before("requestInterceptor()")
    public void interceptorDo(JoinPoint joinPoint) throws BusinessException {
        try {
            Object target = joinPoint.getTarget();
            Object[] args = joinPoint.getArgs();
            String methodName = joinPoint.getSignature().getName();
            Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
            Method method = target.getClass().getMethod(methodName, parameterTypes);
            GlobalInterceptor annotation = method.getAnnotation(GlobalInterceptor.class);
            if (null == annotation) return;
            // 校验登录
            if (annotation.checkLogin() || annotation.checkAdmin())

                // 校验参数
                if (annotation.checkParams()) {
                    validateParams(method, args);
                }
        } catch (Exception e) {
            logger.error("拦截器异常", e);
            throw new BusinessException(e);
        }
    }

    private void validateParams(Method method, Object[] args) {
        if (null == method || null == args) return;
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Object arg = args[i];
            VerifyParam verifyParam = parameter.getAnnotation(VerifyParam.class);
            if (null == verifyParam) continue;
            if (parameter.getParameterizedType().getTypeName().equals("java.lang.String")
                    || parameter.getParameterizedType().getTypeName().equals("java.lang.Integer")
                    || parameter.getParameterizedType().getTypeName().equals("java.lang.Long")) {
                checkValue(arg, verifyParam);
            }
        }
    }

    private void checkLogin(Boolean checkAdmin) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        SessionWebUserDto userDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);

        if (null == userDto){
            throw new BusinessException(ResponseCodeEnum.CODE_901);
        }
        if (checkAdmin && !userDto.isAdmin()) {
            throw new BusinessException(ResponseCodeEnum.CODE_404);
        }
    }


    private void checkValue(Object arg, VerifyParam verifyParam) {
        boolean isNull = arg == null || StringTools.isEmpty(arg.toString());
        int length = arg == null ? 0 : arg.toString().length();

        // 校验空
        if (verifyParam.required() && isNull) {
            logger.error("参数校验失败，参数为空");
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        // 校验长度
        if (!isNull && (verifyParam.max() != -1 && verifyParam.max() < length || verifyParam.min() != -1 && verifyParam.min() > length)) {
            logger.error("参数校验失败，参数长度不符合要求");
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        // 校验正则
        if (!isNull && !StringTools.isEmpty(verifyParam.regex().getRegex()) && !arg.toString().matches(verifyParam.regex().getRegex())) {
            logger.error("参数校验失败，参数不符合正则要求");
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
    }
}